package cn.stimd.spring.context.annotation;

import cn.stimd.spring.beans.factory.annotation.AnnotatedBeanDefinition;
import cn.stimd.spring.beans.factory.config.BeanDefinition;
import cn.stimd.spring.beans.factory.support.BeanDefinitionRegistry;
import cn.stimd.spring.context.ResourceLoaderAware;
import cn.stimd.spring.context.stereotype.Component;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public class ClassPathScanningCandidateComponentProvider implements ResourceLoaderAware {
    static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";    //默认通配符，扫描任意层级目录下的任意名称的class文件
    private final List<TypeFilter> includeFilters = new LinkedList<>();
    private final List<TypeFilter> excludeFilters = new LinkedList<>();
    private ResourcePatternResolver resourcePatternResolver;        //路径解析+资源加载
    private MetadataReaderFactory metadataReaderFactory;
    private ConditionEvaluator conditionEvaluator;
    private Environment environment;

    protected ClassPathScanningCandidateComponentProvider() {}

    public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
        if (useDefaultFilters) {
            registerDefaultFilters();
        }
        setEnvironment(environment);
        setResourceLoader(null);
    }

    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            //1. 加载指定路径下的资源
            basePackage = basePackage.replace('.', '/');        //将包名的.分隔符换成/
            //格式为classpath*:/xx/**/*.class，表示任意类路径下的、指定包路径下的、任意层级目录下的任意名称的class文件
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + basePackage + '/' + DEFAULT_RESOURCE_PATTERN;
            Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);

            for (Resource resource : resources) {
                //2. 将加载的字节流以ASM的方式转换成Class元数据
                MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                //3. 过滤出符合条件的类，创建BeanDefinition
                //3.1 根据TypeFilter和Condition过滤元数据
                if(isCandidateComponent(metadataReader)){
                    ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);

                    //3.2 检查是否为实现类或静态内部类
                    if(isCandidateComponent(sbd)){
                        candidates.add(sbd);
                    }
                }
            }
        }catch (IOException e){
            throw new RuntimeException("扫描classpath时错误", e);
        }
        return candidates;
    }


    //根据排除或包含规则、以及条件判定，过滤出符合条件的候选项
    private boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        //排除需要过滤掉的项（exclude规则的优先级高于include规则）
        for(TypeFilter tf: this.excludeFilters){
            if(tf.match(metadataReader, this.metadataReaderFactory)){
                return false;
            }
        }

        //加载指定规则的项，比如使用@Component注解声明的类
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                //进一步检查Condition
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }


    //通用检查，确保Bean是普通类或静态内部类
    //1) 必须是独立的，即普通类或静态内部类
    //2) 必须是具体的，即非抽象类或接口
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        AnnotationMetadata metadata = beanDefinition.getMetadata();
        return metadata.isIndependent() && metadata.isConcrete();
    }


    //根据条件对候选者进行过滤
    private boolean isConditionMatch(MetadataReader metadataReader) {
        if (this.conditionEvaluator == null) {
            this.conditionEvaluator = new ConditionEvaluator(getRegistry(), getEnvironment(), this.resourcePatternResolver);
        }
        return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
    }


    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
    }


    /**
     * 注册默认的TypeFilter
     */
    protected void registerDefaultFilters(){
        this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    }


    public void addIncludeFilter(TypeFilter includeFilter) {
        this.includeFilters.add(includeFilter);
    }

    public void addExcludeFilter(TypeFilter excludeFilter) {
        this.excludeFilters.add(excludeFilter);
    }


    protected Environment getEnvironment(){
        return this.environment;
    };

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    protected BeanDefinitionRegistry getRegistry(){
        return null;
    }
}
